package com.mrd.frame.controller;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.jdom2.JDOMException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.mrd.frame.domain.PayConfig;
import com.mrd.weixinpay.util.HttpUtil;
import com.mrd.weixinpay.util.PayCommonUtil;
import com.mrd.weixinpay.util.XMLUtil;

/**
 * 微信其它代码，暂时转移到这个新的实现类
 * @author han
 */
/**
 * @author AllisonWang
 */
/**
 * @author AllisonWang
 */
@Controller
public class WeixinPayController {
	private static final Logger	logger	= Logger.getLogger(WeixinPayController.class);
	
	/**
	 * 创建二维码
	 */
	@RequestMapping("/createQRCode")
	public void createQRCode(HttpServletResponse response,
			HttpServletRequest request) {

		// 生成订单
		String orderId = request.getParameter("orderId");
		String orderName = request.getParameter("orderName");
		String orderPrice = request.getParameter("orderPrice");
		// 调统一下单API

		String code_url = "";
		Boolean chinese = false;
		// try {
		// // code_url = unifiedOrder(orderId, orderName,
		// orderPrice).replace("+", "%20");
		// // code_url = unifiedOrder(request, response)
		// // .replace("+", "%20");
		// chinese = isChinese(code_url);
		//
		// // code_url = UrlEncode(code_url);
		// } catch (JDOMException e1) {
		// e1.printStackTrace();
		// } catch (IOException e1) {
		// e1.printStackTrace();
		// }
		// 将返回预支付交易链接（code_url）生成二维码图片
		// 这里使用的是zxing <span
		// style="color:#ff0000;"><strong>说明1(见文末)</strong></span>
		if (!chinese) {
			try {
				int width = 200;
				int height = 200;
				String format = "png";
				Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
				hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
				BitMatrix bitMatrix = new MultiFormatWriter().encode(code_url,
						BarcodeFormat.QR_CODE, width, height, hints);
				OutputStream out = null;
				out = response.getOutputStream();
				MatrixToImageWriter.writeToStream(bitMatrix, format, out);
				out.flush();
				out.close();
			} catch (Exception e) {
			}
		} else {

		}
	}

	/*
	 * 接入仿真系统时秘钥要使用沙箱秘钥，始终获取不到沙箱秘钥，发邮件给腾讯客服后客服回复是是沙箱环境有问题，让直接使用正式系统，
	 * 因此以后开发时别使用沙箱了，直接申请测试经费，在微信正式系统研发测试。
	 */

	public String getSignaturekey(String sign, String nonceStr)
			throws JDOMException, IOException {
		String mch_id = PayConfig.mchIdOriginal; // 商业号
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		packageParams.put("mch_id", mch_id);// 商业号
		packageParams.put("nonce_str", nonceStr);// 十位的随机字符串
		packageParams.put("sign", sign);// 真实支付秘钥采用MD5加密后的签名
		String requestXML = PayCommonUtil.getRequestXml(packageParams);
		System.out.println(requestXML);
		// 发送的字符串： requestXML="<xml>
		// <mch_id>1460239802</mch_id>
		// <nonce_str>1648548893</nonce_str>
		// <sign><![CDATA[BBC40D5EF08D3166C8E05B496BEAA6AD]]></sign>
		// </xml>"
		// 获取沙箱秘钥的api:PayConfig.getSignaturekeyUrl="https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey"
		// 微信端返回的字符串 resXml="<xml>
		// <return_code><![CDATA[FAIL]]></return_code>
		// <return_msg><![CDATA[获取沙箱密钥失败，确认交易密钥是否正确]]></return_msg>
		// </xml>"
		String resXml = HttpUtil.postData(PayConfig.getSignaturekeyUrl,
				requestXML);
		System.out.println(resXml);
		Map map = XMLUtil.doXMLParse(resXml);
		String sigKye = (String) map.get("sandbox_signkey");

		return sigKye;
	}

	/**
	 * 以下情况需要关单： 1，商户订单支付失败需要生成新单号重新发起支付，要对原订单号调用关单，避免重复支付；
	 * 2，系统下单后，用户支付超时，系统退出不再受理，避免用户继续，请调用关单接口。 注意：订单生成后不能马上调用关单接口，最短调用时间间隔为5分钟。
	 * 
	 * @return
	 */
	@RequestMapping("/closeOrder")
	public String closeOrder(Model model) {
		String appid = PayConfig.appidOriginal; // appid
		String mch_id = PayConfig.mchIdOriginal; // 商业号
		String key = PayConfig.apiKeyOriginal; // key
		String currTime = PayCommonUtil.getCurrTime();
		String strTime = currTime.substring(8, currTime.length());
		String strRandom = PayCommonUtil.buildRandom(4) + "";
		String nonce_str = strTime + strRandom;
		String out_trade_no = "20170414003111600";
		SortedMap<Object, Object> params = new TreeMap<Object, Object>();
		params.put("appid", appid);
		params.put("mch_id", mch_id);
		params.put("nonce_str", nonce_str);
		params.put("out_trade_no", out_trade_no);
		String sign = PayCommonUtil.createSign("UTF-8", params, key);
		params.put("sign", sign);
		String requestXML = PayCommonUtil.getRequestXml(params);
		System.out.println("系统发送信息：  " + requestXML);

		// String resXml = HttpUtil.postData(PayConfig.ufdoderUrlTest,
		// requestXML);
		String resXml = HttpUtil.postData(PayConfig.closeOrder, requestXML);
		System.out.println("微信返回信息： " + resXml);
		Map map;
		// 根据微信返回的信息反馈相应的数据给业务系统。
		String retMessage = "";
		try {
			map = XMLUtil.doXMLParse(resXml);
			String return_code = (String) map.get("return_code");
			String result_code = (String) map.get("result_code");
			if ("SUCCESS".equals(result_code) && "SUCCESS".equals(return_code)) {
				retMessage = "成功关闭交易订单。";
			}
			if ("SUCCESS".equals(return_code) && "FAIL".equals(result_code)) {
				String errCode = (String) map.get("err_code");
				if ("ORDERPAID".equals(errCode)) {
					retMessage = "订单已支付，不能发起关单。";
				}
				if ("SYSTEMERROR".equals(errCode)) {
					retMessage = "微信系统异常，请稍后重新调用该API。";
				}
				if ("ORDERCLOSED".equals(errCode)) {
					retMessage = "订单已关闭，无需重复关闭。";
				}
				if ("SIGNERROR".equals(errCode)) {
					retMessage = "签名错误，请检查请求数据是否正确。";
				}
				if ("XML_FORMAT_ERROR".equals(errCode)) {
					retMessage = "请检查数据是否正确。";
					logger.info("请检查XML参数格式是否正确");
				}

			}
			if ("FAIL".equals(return_code)) {
				String errMsg = (String) map.get("return_msg");
				if (!"".equals(errMsg) && errMsg != null) {
					retMessage = errMsg;
					logger.info(errMsg);
				}
			}
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		model.addAttribute("flag", "closeOrder");
		model.addAttribute("msg", retMessage);

		return "weixinpay/result";
	}

	/**
	 * 1,提交退款申请后，通过调用该接口查询退款状态。
	 * 2,退款有一定延时，用零钱支付的退款20分钟内到账，银行卡支付的退款3个工作日后重新查询退款状态。
	 * 
	 * @param model
	 * @return
	 */
	@RequestMapping("/queryRefund")
	public String queryRefund(Model model, HttpServletRequest request,
			HttpServletResponse response) {
		String retm = "";
		String appid = PayConfig.appidOriginal; // appid
		String mch_id = PayConfig.mchIdOriginal; // 商业号
		String key = PayConfig.apiKeyOriginal; // key
		String currTime = PayCommonUtil.getCurrTime();
		String strTime = currTime.substring(8, currTime.length());
		String strRandom = PayCommonUtil.buildRandom(4) + "";
		String nonce_str = strTime + strRandom;
		String out_trade_no = "20170414003171708";
		SortedMap<Object, Object> params = new TreeMap<Object, Object>();
		params.put("appid", appid);
		params.put("mch_id", mch_id);
		params.put("nonce_str", nonce_str);
		params.put("out_trade_no", out_trade_no);
		String sign = PayCommonUtil.createSign("UTF-8", params, key);
		params.put("sign", sign);
		String requestXML = PayCommonUtil.getRequestXml(params);
		System.out.println("系统发送信息：  " + requestXML);

		// String resXml = HttpUtil.postData(PayConfig.ufdoderUrlTest,
		// requestXML);
		String resXml = HttpUtil.postData(PayConfig.refundQuery, requestXML);
		System.out.println("微信返回信息： " + resXml);
		// 退款涉及的字段会比较多，因此直返回解析xml后的map给业务系统，让其根据需求使用相关的数据。（map的key详见查询退款API）
		Map map = new TreeMap();
		// 根据微信返回的信息反馈相应的数据给业务系统。

		try {
			map = XMLUtil.doXMLParse(resXml);
			map.put("type", "queryRefund");
			String return_code = (String) map.get("return_code");
			String result_code = (String) map.get("result_code");
			if ("SUCCESS".equals(result_code)) {
				retm = "退款查询成功,已将数据反馈至业务系统。";
			} else {
				retm = (String) map.get("err_code_des");
			}
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		model.addAttribute("flag", "queryRefund");
		model.addAttribute("msg", retm);
		// TODO 向业务系统反馈查询结果,后期开放。
		// try {
		// printToSystemAsMap(response, map);
		// } catch (IOException e) {
		// e.printStackTrace();
		// }

		return "weixinpay/result";
	}

	/**
	 * 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致，通过对账单核对后可校正支付状态。 注意：
	 * 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中，跟原支付单订单号一致；
	 * 2、微信在次日9点启动生成前一天的对账单，建议商户10点后再获取； 3、对账单中涉及金额的字段单位为“元”。
	 * 4、对账单接口只能下载三个月以内的账单。
	 * tips:不推荐业务系统使用接口下载对账单增加业务系统负荷，建议业务系统在微信商户平台->交易中心->交易账单
	 * 中可以选择一个时间段内的数据进行下载。
	 * 
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	@RequestMapping("/downBill")
	public String downBill(HttpServletRequest request,
			HttpServletResponse response, Model model) {
		String retMsg = "";
		String appid = PayConfig.appidOriginal; // appid
		String mch_id = PayConfig.mchIdOriginal; // 商业号
		String key = PayConfig.apiKeyOriginal; // key
		String currTime = PayCommonUtil.getCurrTime();
		String strTime = currTime.substring(8, currTime.length());
		String strRandom = PayCommonUtil.buildRandom(4) + "";
		String nonce_str = strTime + strRandom;
		String billDate = "20170420";// 需下载的对账单的日期，格式“yyyymmdd”
		// 账单类型，可取的值的意义：1，ALL，返回当日所有订单信息，默认值 ；2，SUCCESS，返回当日成功支付的订单
		// ；3，REFUND，返回当日退款订单
		// ；4，RECHARGE_REFUND，返回当日充值退款订单（相比其他对账单多一栏“返还手续费”）
		String billType = "ALL";
		// String tarType = "GZIP";//
		// 非必传参数，固定值：GZIP，返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
		SortedMap<Object, Object> reqParams = new TreeMap<Object, Object>();
		reqParams.put("appid", appid);
		reqParams.put("mch_id", mch_id);
		reqParams.put("nonce_str", nonce_str);
		reqParams.put("bill_date", billDate);
		reqParams.put("bill_type", billType);
		// reqParams.put("tar_type", tarType);
		String sign = PayCommonUtil.createSign("UTF-8", reqParams, key);
		reqParams.put("sign", sign);
		String requestXML = PayCommonUtil.getRequestXml(reqParams);
		System.out.println("系统发送信息：  " + requestXML);

		String resXml = HttpUtil.postData(PayConfig.downBill, requestXML);
		System.out.println("微信返回信息： " + resXml);
		// 退款涉及的字段会比较多，因此直返回解析xml后的map给业务系统，让其根据需求使用相关的数据。（map的key详见查询退款API）
		Map map = new TreeMap<Object, Object>();
		model.addAttribute("flag", "downBill");
		model.addAttribute("retMsg", resXml);
		map.put("type", "downBill");
		map.put("data", resXml);
		// TODO 向业务系统反馈查询结果,后期开放。
		// try {
		// printToSystemAsMap(response, map);
		// } catch (IOException e) {
		// e.printStackTrace();
		// }

		return "weixinpay/result";
	}

	/**
	 * 生成毫秒级字符串
	 * @return
	 */
	@RequestMapping("/createId")
	public String createId() {
		String id = String.valueOf(System.currentTimeMillis());
		System.out.println(id);

		return id;

	}

}
